﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Configuration;
using System.Data;
using System.Data.Common;
using log4net;

namespace LanguageDetector.Data
{
    public enum QueryType : byte
    {
        ReadWrite = 0,
    }

    public enum QueryDB : byte
    {
        LangDet = 0,
    }

    public sealed class Query
    {
        public Query()
        {
            CommandType = CommandType.Text;
        }
        public string Text { get; set; }

        List<DbParameter> _params = new List<DbParameter>();
        public List<DbParameter> Params
        {
            get { return _params; }
            set
            {
                _params.Clear();
                if (value != null)
                    _params.AddRange(value);
            }
        }
        public CommandType CommandType { get; set; }
        public QueryDB QueryDB { get; set; }
        public QueryType QueryType { get; set; }
    }

    #region lamda & extension demo
    public static partial class ExtensionMethods
    {
        static ILog logger = LogManager.GetLogger(typeof(ExtensionMethods));

        public static List<Exception> ExecuteReader(this Query q, Action<DbDataReader> reader)
        {
            return q.ExecuteReader(CommandBehavior.SequentialAccess, reader);
        }

        public static List<Exception> ExecuteReader(this Query q, CommandBehavior behavior, Action<DbDataReader> reader)
        {
            var errors = new List<Exception>();
            try
            {
                if (q != null && !string.IsNullOrEmpty(q.Text) && reader != null)
                {
                    var confKey = q.QueryDB.ToString() + q.QueryType.ToString();
                    var conf = ConfigurationManager.ConnectionStrings[confKey];
                    if (conf == null)
                        errors.Add(new ConfigurationErrorsException("Configuration key is missing: " + confKey));
                    else
                    {
                        var prod = DbProviderFactories.GetFactory(conf.ProviderName);
                        using (var conn = prod.CreateConnection())
                        {
                            conn.ConnectionString = conf.ConnectionString;
                            conn.Open();
                            using (var cmd = conn.CreateCommand())
                            {
                                cmd.CommandText = q.Text;
                                cmd.CommandType = q.CommandType;
                                cmd.Parameters.AddRange(q.Params.ToArray());
                                using (var dr = cmd.ExecuteReader(behavior))
                                {
                                    do
                                    {
                                        if (dr.HasRows)
                                        {
                                            while (dr.Read())
                                            {
                                                reader(dr);
                                            }
                                        }
                                    } while (dr.NextResult());
                                    dr.Close();
                                }
                            }
                            conn.Close();
                        }
                    }
                }
                else
                    errors.Add(new ArgumentNullException("Can't execute. Query object or it's Text property is null or reader action is null."));
            }
            catch (Exception ex) { errors.Add(ex); }
            finally { errors.ForEach(e => logger.Error(q, e)); }
            return errors;
        }

        public static List<Exception> ExecuteNoneReader(this Query q)
        {
            var errors = new List<Exception>();
            try
            {
                if (q != null && !string.IsNullOrEmpty(q.Text))
                {
                    var confKey = q.QueryDB.ToString() + q.QueryType.ToString();
                    var conf = ConfigurationManager.ConnectionStrings[confKey];
                    if (conf == null)
                        errors.Add(new ConfigurationErrorsException("Configuraiton key is missing: " + confKey));
                    else
                    {
                        var prod = DbProviderFactories.GetFactory(conf.ProviderName);
                        using (var conn = prod.CreateConnection())
                        {
                            conn.ConnectionString = conf.ConnectionString;
                            conn.Open();
                            using (var cmd = conn.CreateCommand())
                            {
                                cmd.CommandText = q.Text;
                                cmd.CommandType = q.CommandType;
                                cmd.Parameters.AddRange(q.Params.ToArray());
                                cmd.ExecuteNonQuery();
                            }
                            conn.Close();
                        }
                    }
                }
                else
                    errors.Add(new ArgumentNullException("Query or it's Text property is null"));
            }
            catch (Exception ex) { errors.Add(ex); }
            finally { errors.ForEach(e => logger.Error(q, e)); }
            return errors;
        }
    }
    #endregion
}
